/********************************************
除法开方模块功能描述：
    输入规格化的浮点数
    输出除法开方的结果和余数

    双精度数：1位符号位，11位指数位，52位尾数位 共64位
    单精度数：1位符号位，8位指数位，23位尾数位 共31位

    商数字集选用：{-2，-1，0，1，2}
********************************************/

module div_sqrt(
    input       [53-1:0]        x           ,   //被除数或者部分余数
    input       [53-1:0]        d           ,   //除数或者移位后的部分余数

    input       [8-1:0]         rR          ,   //部分余数，用来和查找表输出界限比较，获得商数字的部分余数，已移位，1位符号位，3位整数位，四位小数位

    input       [6-1:0]         sqrt_j      ,   //部分开方值，就是没完全算完的开方的商q

    input                       div_or_sqrt ,   //指示是除法还是开方 1：div 0:sqrt

    input       [55-1:0]        rw_sum      ,   //部分余数的sum位，未移位
    input       [55-1:0]        rw_carry    ,   //部分余数的carry位，未移位

    output      [3-1:0]        q_i          ,   //每一回迭代产生的qi
//    output      [53-1:0]        rw          ,   //部分余数
//    output      [53-1:0]        sqrt_j_53   ,   //全长的开方值
    output      [8-1:0]         CLA_select  ,   //给下一拍的查找表的输入

    output      [55-1:0]        rw_sum_o    ,   //压缩器输出的部分余数sum
    output      [55-1:0]        rw_carry_o      //压缩器输出的部分余数carry
    
);
        

wire        [8-1:0]             rw_start_8      ;       //被除数或部分余数前8位
wire        [4-1:0]             d_start_4       ;       //除数的4位小数
wire        [3-1:0]             q_one_round     ;       //算出来的商编码第一位代表符号位，后两位代表数字

wire        [6-1:0]             table_input     ;       //除法开方查找表的输入
wire        [7-1:0]             table_output_u2 ;       //查找表上限u2
wire        [7-1:0]             table_output_p2 ;       //查找表p2界限
wire        [7-1:0]             table_output_p1 ;       //查找表p1界限

wire                            g               ;       //guard位
wire                            r               ;       //round位
wire                            s               ;       //sticky位

wire                            rw_smaller_u2   ;       //部分余数是否小于最大上限
wire                            rw_smaller_p2   ;       //部分余数是否小于p2界限
wire                            rw_smaller_p1   ;       //部分余数是否小于p1界限

wire        [3-1:0]             q_i             ;       //某一次循环产生的商 第三位代表符号位，后两位代表数字位
wire        [3-1:0]             q_i_pos         ;       //当部分余数是正数的时候选出来的商
wire        [3-1:0]             q_i_neg         ;       //当部分余数是负数的时候选出来的商

wire        [8-1:0]             rw_tail         ;       //部分余数的尾数，用来查找表折叠，一位符号位

wire        [55-1:0]            d_shift_0_pos   ;       //1倍的除数d，正数，和最长的移位位宽保持一致
wire        [55-1:0]            d_shift_0_neg   ;       //1倍的除数d，负数
wire        [55-1:0]            d_shift_1_pos   ;       //2倍的除数d，正数，一位符号位，移位1位，加上数据本来的53位
wire        [55-1:0]            d_shift_1_neg   ;       //2倍的除数d，负数，一位符号位，移位1位，加上数据本来的53位
wire        [56-1:0]            d_shift_2_pos   ;       //4倍的除数d
wire        [56-1:0]            d_shift_2_neg   ;

wire        [9-1:0]             d_shift_1_pos_9 ; 
wire        [9-1:0]             d_shift_1_neg_9 ; 
wire        [9-1:0]             d_shift_2_pos_9 ; 
wire        [9-1:0]             d_shift_2_neg_9 ;

wire        [9-1:0]             sum_csa         ;       //sum送入3:2压缩器的前几位
wire        [9-1:0]             carry_csa       ;       //carry送入3:2压缩器的前几位

wire        [9-1:0]             smcsa_p4d       ;       //32压缩器输出的sum
wire        [9-1:0]             smcsa_n4d       ;
wire        [9-1:0]             smcsa_p2d       ;
wire        [9-1:0]             smcsa_n2d       ;
wire        [9-1:0]             smcsa_0d        ;

wire        [9-1:0]             cocsa_p4d       ;       //32压缩器输出的carry
wire        [9-1:0]             cocsa_n4d       ;
wire        [9-1:0]             cocsa_p2d       ;
wire        [9-1:0]             cocsa_n2d       ;
wire        [9-1:0]             cocsa_0d        ;

reg         [55-1:0]            d_mul_q         ;       //除数d和商q的乘积，根据查找表的输出商是什么选择对应的乘积结果赋给d_mul_q

wire        [5-1:0]             CLA_low4_n4d    ;       //CLA加法器低四位
wire        [5-1:0]             CLA_low4_n2d    ;       //CLA加法器低四位
wire        [5-1:0]             CLA_low4_0d     ;       //CLA加法器低四位
wire        [5-1:0]             CLA_low4_p2d    ;       //CLA加法器低四位
wire        [5-1:0]             CLA_low4_p4d    ;       //CLA加法器低四位

wire        [5-1:0]             CLA_high4_n4d   ;       //CLA加法器高四位
wire        [5-1:0]             CLA_high4_n2d   ;       //CLA加法器高四位
wire        [5-1:0]             CLA_high4_0d    ;       //CLA加法器高四位
wire        [5-1:0]             CLA_high4_p2d   ;       //CLA加法器高四位
wire        [5-1:0]             CLA_high4_p4d   ;       //CLA加法器高四位

wire        [8-1:0]             CLA_output_n4d  ;       //CLA最终8位输出
wire        [8-1:0]             CLA_output_n2d  ;       //CLA最终8位输出
wire        [8-1:0]             CLA_output_0d   ;       //CLA最终8位输出
wire        [8-1:0]             CLA_output_p2d  ;       //CLA最终8位输出
wire        [8-1:0]             CLA_output_p4d  ;       //CLA最终8位输出
wire        [8-1:0]             CLA_mux         ;       //通过商选择CLA输出的结果

wire        [55-1:0]            rw_sum_shift    ;       //输入进来的部分余数移位
wire        [55-1:0]            rw_carry_shift  ;       //输入进来的部分余数移位

wire                            d_n_mux         ;       //当rw-dq中q是正数的时候，rw要加dq的补码，所以末尾要有加一操作

//       assign q[52] = 1'b1;    //商的首位默认为1
assign table_input = div_or_sqrt ? {1'b0, d[52:48]} :  sqrt_j;  //判断是除法还是开方，选择查找表的输入

/***************************
查找表 
    {2Si}δ*16   16  17  18  19  20  21  22  23  24 
      p1(i)*16   8   9   9  10  10  11  11  12  12 
      p2(i)*16  24  26  27  29  30  32  33  35  36 
      U2(i)*16  50  48  50  53  56  58  61  64  72 

    {2Si}δ*16   25  26  27  28  29  30  31  32  
      p1(i)*16  13  13  15  14  15  15  16  16  
      p2(i)*16  38  39  41  42  44  45  47  48  
      U2(i)*16  69  72  74  77  80  82  85  93  
****************************/


//---------------------通过查找表找出商---------------------------
//建立查找表
always @(*) begin
    case (table_input)
        6'b010000:begin table_output_u2 = 7'd50; table_output_p2 = 7'd24; table_output_p1 7'd 8;     end
        6'b010001:begin table_output_u2 = 7'd48; table_output_p2 = 7'd26; table_output_p1 7'd 9;     end
        6'b010010:begin table_output_u2 = 7'd50; table_output_p2 = 7'd27; table_output_p1 7'd 9;     end
        6'b010011:begin table_output_u2 = 7'd53; table_output_p2 = 7'd29; table_output_p1 7'd10;     end
        6'b010100:begin table_output_u2 = 7'd56; table_output_p2 = 7'd30; table_output_p1 7'd10;     end
        6'b010101:begin table_output_u2 = 7'd58; table_output_p2 = 7'd32; table_output_p1 7'd11;     end
        6'b010110:begin table_output_u2 = 7'd61; table_output_p2 = 7'd33; table_output_p1 7'd11;     end
        6'b010111:begin table_output_u2 = 7'd64; table_output_p2 = 7'd35; table_output_p1 7'd12;     end
        6'b011000:begin table_output_u2 = 7'd72; table_output_p2 = 7'd36; table_output_p1 7'd12;     end
        6'b011001:begin table_output_u2 = 7'd69; table_output_p2 = 7'd38; table_output_p1 7'd13;     end
        6'b011010:begin table_output_u2 = 7'd72; table_output_p2 = 7'd39; table_output_p1 7'd13;     end
        6'b011011:begin table_output_u2 = 7'd74; table_output_p2 = 7'd41; table_output_p1 7'd15;     end
        6'b011100:begin table_output_u2 = 7'd77; table_output_p2 = 7'd42; table_output_p1 7'd14;     end
        6'b011101:begin table_output_u2 = 7'd80; table_output_p2 = 7'd44; table_output_p1 7'd15;     end
        6'b011110:begin table_output_u2 = 7'd82; table_output_p2 = 7'd45; table_output_p1 7'd15;     end
        6'b011111:begin table_output_u2 = 7'd85; table_output_p2 = 7'd47; table_output_p1 7'd16;     end
        6'b100000:begin table_output_u2 = 7'd93; table_output_p2 = 7'd48; table_output_p1 7'd16;     end
    endcase
end

assign rw_tail = rR[7] ? {1'b0, rR[6:0]} + 8'b1 : {1'b0, rR[6:0]};  //对部分余数进行折叠，和查找表的界限比较

assign rw_smaller_u2 = rw_tail < {1'b0, table_output_u2}      ?       1'b1 : 1'b0;    //1：小于 0：大于
assign rw_smaller_p2 = rw_tail < {1'b0, table_output_p2}      ?       1'b1 : 1'b0;    //1：小于 0：大于
assign rw_smaller_p1 = rw_tail < {1'b0, table_output_p1}      ?       1'b1 : 1'b0;    //1：小于 0：大于

//当部分余数是正数的时候，如果部分余数小于p1界限：商为0，如果部分数小于p2界限，大于p1界限：商为1，如果部分余数大于p2界限，小于u2界限：商为2
assign q_i_pos = rw_smaller_p1 ? 3'b0 :
                                 rw_smaller_p2  ? 3'b001 :
                                                  rw_smaller_u2 ? 3'b010 : 3'b000 ;  

//当部分余数是负数的时候，如果部分余数小于p1界限：商为0，如果部分数小于p2界限，大于p1界限：商为-1，如果部分余数大于p2界限，小于u2界限：商为-2
assign q_i_neg = rw_smaller_p1 ? 3'b000 :
                                 rw_smaller_p2  ? 3'b111 :
                                                  rw_smaller_u2 ? 3'b110 : 3'b000 ;
                                                

assign q_i = rR[7] ? q_i_neg : q_i_pos ;    //根据部分余数的正负选择最终的正的商或者负的商

//------------------------------查找表找出商 end--------------------------


//------------------------------同时计算商为 -2 -1 0 1 2 时的部分余数，并通过商选择结果------------------
assign d_shift_0_pos = {2'b0, d};
assign d_shift_0_neg = {2'b111, ~d};

assign d_shift_1_pos = {1'b0, d, 1'b0};
assign d_shift_1_neg = {1'b1, ~d, 1'b1};

assign d_shift_2_pos = {1'b0, d, 2'b0};
assign d_shift_2_neg = {1'b1, ~d, 2'b11};


assign d_shift_1_pos_9 = d_shift_1_pos[55:47];
assign d_shift_1_neg_9 = d_shift_1_neg[55:47];
assign d_shift_2_pos_9 = d_shift_1_pos[55:47];
assign d_shift_2_neg_9 = d_shift_1_neg[55:47];

always@(*) begin
    case(q_i)
    3'b010:  d_mul_q = d_shift_1_pos;   //2
    3'b001:  d_mul_q = d_shift_0_pos;   //1
    3'b000:  d_mul_q = 55'b0        ;   //0           
    3'b111:  d_mul_q = d_shift_0_neg;   //-1
    3'b110:  d_mul_q = d_shift_1_neg;   //-2
    default: d_mul_q = 55'b0;
    endcase
end


sum_csa = {rw_sum[54], rw_sum[51:44]};
carry_csa = {rw_carry[53], rw_carry[50:43]};

//取smu和carry的前7位和乘积q*d的前7位送入3:2压缩器压缩，然后送入CLA加法器进行加法
genvar i;
generate 
    for(i=0; i<9 ;i=i+1) begin
        csa32 u_csa32_n4d(.d0(sum_csa[i]), .d1(carry_csa[i]), .ci(d_shift_2_neg_9[i]), .sum(smcsa_n4d[i]), .co(cocsa_n4d[i]));
        csa32 u_csa32_n2d(.d0(sun_csa[i]), .d1(carry_csa[i]), .ci(d_shift_1_neg_9[i]), .sum(smcsa_n2d[i]), .co(cocsa_n2d[i]));
        csa32 u_csa32_p0d(.d0(sun_csa[i]), .d1(carry_csa[i]), .ci(1'b0              ), .sum(smcsa_0d[i] ), .co(cocsa_0d[i] ));
        csa32 u_csa32_p2d(.d0(sun_csa[i]), .d1(carry_csa[i]), .ci(d_shift_1_pos_9[i]), .sum(smcsa_p2d[i]), .co(cocsa_p2d[i]));
        csa32 u_csa32_p4d(.d0(sun_csa[i]), .d1(carry_csa[i]), .ci(d_shift_2_pos_9[i]), .sum(smcsa_p4d[i]), .co(cocsa_p4d[i]));
    end
endgenerate


//CLA加法器低四位相加
CLA_4(.a(smcsa_n4d[4:1]), .b(cocsa_n4d[3:0]), .c0(1'b0), .result(CLA_low4_n4d));
CLA_4(.a(smcsa_n2d[4:1]), .b(cocsa_n2d[3:0]), .c0(1'b0), .result(CLA_low4_n2d));
CLA_4(.a(smcsa_0d[4:1] ), .b(cocsa_0d[3:0] ), .c0(1'b0), .result(CLA_low4_0d ));
CLA_4(.a(smcsa_p2d[4:1]), .b(cocsa_p2d[3:0]), .c0(1'b0), .result(CLA_low4_p2d));
CLA_4(.a(smcsa_p4d[4:1]), .b(cocsa_p4d[3:0]), .c0(1'b0), .result(CLA_low4_p4d));

//CLA加法器高四位相加
CLA_4(.a(smcsa_n4d[8:5]), .b(cocsa_n4d[7:4]), .c0(CLA_low4_n4d[4]), .result(CLA_high4_n4d));
CLA_4(.a(smcsa_n4d[8:5]), .b(cocsa_n4d[7:4]), .c0(CLA_low4_n2d[4]), .result(CLA_high4_n2d));
CLA_4(.a(smcsa_n4d[8:5]), .b(cocsa_n4d[7:4]), .c0(CLA_low4_0d[4] ), .result(CLA_high4_0d ));
CLA_4(.a(smcsa_n4d[8:5]), .b(cocsa_n4d[7:4]), .c0(CLA_low4_p2d[4]), .result(CLA_high4_p2d));
CLA_4(.a(smcsa_n4d[8:5]), .b(cocsa_n4d[7:4]), .c0(CLA_low4_p4d[4]), .result(CLA_high4_p4d));


assign CLA_output_n4d = {CLA_high4_n4d[3:0], CLA_low4_n4d[3:0]};
assign CLA_output_n2d = {CLA_high4_n2d[3:0], CLA_low4_n2d[3:0]};
assign CLA_output_0d  = {CLA_high4_0d[3:0] , CLA_low4_0d[3:0] };
assign CLA_output_p2d = {CLA_high4_p2d[3:0], CLA_low4_p2d[3:0]};
assign CLA_output_p4d = {CLA_high4_p4d[3:0], CLA_low4_p4d[3:0]};

always @(*) begin
    case (q_i)
        3'b010:  CLA_select = CLA_output_p4d;   //2
        3'b001:  CLA_select = CLA_output_p2d;   //1
        3'b000:  CLA_select = CLA_output_0d ;   //0
        3'b111:  CLA_select = CLA_output_n2d;   //-1
        3'b110:  CLA_select = CLA_output_n4d;   //-2
        default: CLA_select = 8'b0;
    endcase
end
//--------------------------------CLA部分结束------------------------------------


//---------------------------------结构图右半部分全长压缩器部分-------------------
assign d_n_mux = q_i[2] == 1'b0 ? 1'b1 : 1'b0;  //当q_i的符号位为0的时候，-qd是负数，补码要加一，mux选择1

assign rw_sum_shift = {rw_sum[54], rw_sum[52:0], 1'b0}; //一位符号位，移位后的sum，一位移位后补的0
assign rw_carry_shift = {rw_carry[53], rw_carry[51:0], 1'b0, d_n_mux};  //一位符号位，移位后的carry，移位补的0，一个补码取反的加一

genvar j;
generate
    for(j=0; j<55; j=j+1) begin
        csa32 u_csa32_rw(.d0(rw_sum_shift[j]), .d1(rw_carry_shift[j]), .ci(d_mul_q[j]), .sum(rw_sum_o[j]), .co(rw_carry_o[j]));
    end
endgenerate
//---------------------------------全长压缩器部分结束----------------------------
        
endmodule






